from script.util.Print import Print, ColorPrint


class ProgressBar(object):
    _width: int
    _progress_color: int
    _foreground_color: int
    _background_color: int

    _max_block_count: int
    _title: str
    _max_progress: int
    _cur_progress: int

    _display_progress: int

    def __init__(self, width: int,
                 progress_color: int = Print.WHITE,
                 foreground_color: int = Print.DEFAULT, background_color: int = Print.DEFAULT,
                 show_in_single_line: bool = True):
        self._width = width
        self._max_block_count = self._width - 2

        self._progress_color = progress_color
        self._foreground_color = foreground_color
        self._background_color = background_color
        self._show_in_single_line = show_in_single_line

        self._title = ''
        self._max_progress = 100
        self._cur_progress = 0
        self._display_progress = 0

    def __enter__(self):
        self.begin()
        return self

    def __exit__(self, exc_type, exc_val, exc_tb):
        self.end()

    def begin(self):
        self.set_cur(0)

    def end(self):
        Print.edl()

    def set_title(self, title: str):
        self._title = title
        self._draw()

    def set_width(self, width: int):
        if self._width != width:
            self._width = width
            self._max_block_count = self._width - 2

            display_progress = self.generate_display_progress()
            if self._display_progress != display_progress:
                self._display_progress = display_progress
                self._draw()

    def set(self, cur_progress: int, max_progress: int, title: str = None):
        dirty = False

        # set progress
        if self._max_progress != max_progress:
            self._max_progress = max_progress

        if self._cur_progress != cur_progress:
            self._cur_progress = cur_progress

        display_progress = self.generate_display_progress()
        if self._display_progress != display_progress:
            self._display_progress = display_progress
            dirty = True

        # set title
        if title is not None and self._title != title:
            self._title = title
            dirty = True

        if dirty:
            self._draw()

    def set_max(self, max_progress: int):
        if self._max_progress != max_progress:
            self._max_progress = max_progress

        display_progress = self.generate_display_progress()
        if self._display_progress != display_progress:
            self._display_progress = display_progress
            self._draw()

    def set_cur(self, cur_progress: int):
        if self._cur_progress != cur_progress:
            self._cur_progress = cur_progress

        display_progress = self.generate_display_progress()
        if self._display_progress != display_progress:
            self._display_progress = display_progress
            self._draw()

    def generate_display_progress(self) -> int:
        return (self._cur_progress * self._max_block_count) // self._max_progress

    def _draw(self):
        display_text = '% 3d%% %s' % (self._cur_progress*100//self._max_progress, self._title)
        display_text += (' ' * (self._max_block_count - len(display_text)))

        display_text_l = display_text[0:self._display_progress]
        display_text_r = display_text[self._display_progress:]

        if self._show_in_single_line:
            Print.return_line()

        with ColorPrint() as p:
            p.append('[', self._foreground_color, self._background_color)\
             .append(display_text_l, self._foreground_color, self._progress_color) \
             .append(display_text_r, self._foreground_color, self._background_color) \
             .append(']', self._foreground_color, self._background_color)

        if not self._show_in_single_line:
            Print.next_line()
